package cn.hbads.support.compare;

import cn.hbads.support.compare.supoort.BigDecimalComparator;
import cn.hbads.support.compare.supoort.NoOpJaversRepository;
import cn.hbads.support.compare.supoort.StringPropertyComparator;
import cn.hbads.support.error.ErrorType;
import cn.hbads.support.json.JsonUtil;
import cn.hbads.support.json.support.SelfJsonNodeComparator;
import cn.hbads.support.structure.result.ComputeResult;
import cn.hbads.support.structure.tuple.Tuple;
import com.fasterxml.jackson.databind.JsonNode;
import org.javers.core.Javers;
import org.javers.core.JaversBuilder;
import org.javers.core.diff.Diff;

import java.math.BigDecimal;

/**
 * <b>对象比较工具类，封装Javers框架</b>
 *
 * @author yvvb
 * @date 2025/5/4
 */
public final class CompareUtil {
    private static final Javers JAVERS;
    private static final SelfJsonNodeComparator JSON_NODE_COMPARATOR = new SelfJsonNodeComparator();

    static {
        JAVERS = JaversBuilder.javers()
                .registerJaversRepository(new NoOpJaversRepository())
                .registerValue(BigDecimal.class, new BigDecimalComparator())
                .registerCustomType(String.class, new StringPropertyComparator())
                // .registerValue(String.class, new StringComparator()) 因为这里比对null与非null不会进入比较器，所以必须用registerCustomType
                .build();
    }

    private CompareUtil() {
    }

    public static Diff compare(Object left, Object right) {
        return JAVERS.compare(left, right);
    }

    public static <T> Diff compare(Tuple<T, T> comparePair) {
        return JAVERS.compare(comparePair.getValue1(), comparePair.getValue2());
    }

    public static ComputeResult<Boolean, ErrorType> isJsonNodeEqual(Object obj1, Object obj2) {
        ComputeResult<JsonNode, ErrorType> obj1JsonNodeResult = JsonUtil.readToJsonNode(obj1);
        if (!obj1JsonNodeResult.isSuccess()) {
            return obj1JsonNodeResult.mapErr(t -> null);
        }
        ComputeResult<JsonNode, ErrorType> obj2JsonNodeResult = JsonUtil.readToJsonNode(obj2);
        if (!obj2JsonNodeResult.isSuccess()) {
            return obj2JsonNodeResult.mapErr(t -> null);
        }
        if (obj1JsonNodeResult.get().equals(JSON_NODE_COMPARATOR, obj2JsonNodeResult.get())) {
            return ComputeResult.success(Boolean.TRUE);
        } else {
            return ComputeResult.success(Boolean.FALSE);
        }
    }
}
